#ifndef _EVENTLOOP_H    // 头文件写错也可能引起此行报错
#define _EVENTLOOP_H

#include "05_TCPconnection.hpp"
#include "sys/epoll.h"
#include <vector>
#include <map>
#include <functional>

/* 知识点，回调函数四步骤：
 * 1：定义回调函数 | 厨师准备好做菜的步骤：编写处理事件的函数；
 * 2：声明函数指针类型（可选但推荐） | 菜单上标准菜的类型（炒菜/汤品等）：用using或者typedef定义函数的指针类型
 * 3: 注册回调函数 | 顾客点餐（告诉服务员要哪个菜）：将回调函数传给接收者，如本文件void set_connection_callback
 * 4：触发回调函数 | 服务员通知厨师做菜：在特定时间发生时，调用已注册的回调函数，如本文件handle_new_connection
 * 5：执行回调函数 | 厨师做菜：回调函数被调用，执行其预定功能；
 * */

class Acceptor;

namespace xy{

// 2: 定义回调函数类型(给这个形状的函数起个名字)
using TCP_Connection_Callback = std::function<void(const TCPconnection::TCPconnectionPtr&)>;
using TCP_Message_Callback = std::function<void(const TCPconnection::TCPconnectionPtr&, const std::string&)>;
using TCP_Close_Callback = std::function<void(const TCPconnection::TCPconnectionPtr&)>;

class Event_Loop
{
friend class TCPconnection;
public:
    Event_Loop(Acceptor&);  // 构造函数需要初始化引用成员
    ~Event_Loop();
    
    void loop();
    void unloop();
    void wait_epollfd();
    
    //// 抄错了，在Event_Loop类内定义成员函数时，不应添加Event_Loop::前缀
    //void Event_Loop::handle_connection_callback();
    //void Event_Loop::handle_message_callback();
    //void Event_Loop::handle_close_callback();

    // 3: 注册回调函数(回调函数的接口) | 存储传递进来的回调函数，就像服务员的点餐记录本，暂时保存顾客点的菜
    void set_connection_callback(TCP_Connection_Callback);
    void set_message_callback(TCP_Message_Callback);
    void set_close_callback(TCP_Close_Callback);
    
    // 4: 触发回调函数 | 特定时间发生时，调用之前注册的回调函数，就像菜做好了，服务员通知顾客取餐 
    void handle_connection_callback();
    void handle_message_callback();
    void handle_close_callback();


private:
    //Event_Loop();     // 构造函数需要初始化引用成员，而且最好放在public

    // 老师把这三个函数设置为私有，可能因为不太想让用户调用，我这边用友元试试，不行的话就公有吧
    int create_epollfd();
    void add_epoll_read_event(int);
    void del_epoll_read_event(int);
   
    // 3: 注册回调函数，存储回调函数的“容器”
    TCP_Connection_Callback _on_connection = nullptr;
    TCP_Message_Callback _on_message = nullptr;
    TCP_Close_Callback _on_close = nullptr;

private:
    int                                             _epfd;      // 需要监听lisren_fd
    Acceptor&                                       _acceptor;  // 关联关系，此处可以使用类的前向声明，不需要头文件
    std::vector<struct epoll_event>                 _evt_vec;   // 增加头文件
    std::map<int, TCPconnection::TCPconnectionPtr>  _conns;     // 修改为智能指针
    bool                                            _is_looping;
};
}

#endif
